xlv.obj.treeDnD={
	extend:function(){
		this.extend('xlv.obj.tree');
	},	
	implement:function(){
		this.implement('xlv.imp.dnd');
	},
	properties:{
		dnd_allowed:true,
		dnd_dropEffect:'move',//copy,move,link,none
		dnd_dropTarget:'child',//'child', //before, after
		dnd_dropSelected:true,
		dnd_dropExpanded:true
	},
	method:{
		initial:function(){
			this.dnd_properties.ghostFloat=true;
			this.$super('xlv.obj.tree.initial');
			this.dnd_enabled(true);
		},
		removeTree:function(item){
			var select=this.select_getSelected();
			item=(item||select);
			if(item==select) this.select_clear(item);
			if(item) {
				var p=xlv.util.findParent(item,{tag:'li'},{object:this});
				var pul=xlv.util.findParent(item,{tag:'ul'},{object:this});
				var sibp=xlv.util.findPrevSibling(item,{tag:'li'});
				var sibn=xlv.util.findNextSibling(item,{tag:'li'});
				item.parentNode.removeChild(item);
				if(sibp==null && sibn==null) pul.parentNode.removeChild(pul);
				this.updateStyle(sibn||sibp||p);
			}
		},
		appendTreeChild:function(item,parent){
			parent=parent||this.select_getSelected();
			var ul=xlv.util.findDirectChild(parent,{tag:'ul'});
			if(!ul)	parent.appendChild(ul=document.createElement('ul'));
			ul.appendChild(item);
			this.updateStyle(item);
			if(this.$P.dnd_dropExpanded) this.expand(parent,true);
			if(this.$P.dnd_dropSelected) this.select_item(item);
		},
		insertTreeBefore:function(item,sibling){
			sibling=sibling||this.select_getSelected();
			sibling.parentNode.insertBefore(item,sibling);
			this.updateStyle(item);
			if(this.$P.dnd_dropSelected) this.select_item(item);
		},
		insertTreeAfter:function(item,sibling){
			sibling=sibling||this.select_getSelected();
			var next=xlv.util.findNextSibling(sibling,{tag:'li'});
			if(next)next.parentNode.insertBefore(item,next);
			else sibling.parentNode.appendChild(item);
			this.updateStyle(item);
			if(this.$P.dnd_dropSelected) this.select_item(item);
		},
		/*dnd implement*/
		dnd_dragable:function(e){
			if(!this.$P.dnd_allowed) return false;
			var src=(e.srcElement||e.target);
			if(xlv.util.isTag(src, 'li') || xlv.util.isTag(src, 'ul')) return false;
			src=this.targetElement(src,{tag:'li'});
			if(!src) return false;
			// root cannot be dragged
			if(xlv.util.levelOfDescendant(this,src,{tag:'li'})<= 1 && xlv.util.siblings(src,{tag:'li'}).length < 1) return false; 
			return src;
		},
		dnd_createGhost:function(){
			var p=this.dnd_properties;
			var div=document.createElement('div');
			var ul=document.createElement('ul');
			div.appendChild(ul);
			div.className=this.className;
			var src=p.source.cloneNode(true);
			while(src.firstChild)ul.appendChild(src.firstChild);
			p.ghostElement=div;
			Element.setStyle(p.ghostElement,{left:(p._startXY[0]+1)+'px',top:(p._startXY[1]+1)+'px',position:'absolute',zIndex:xlv.sys.zIndexDnd});
			Element.setOpacity(p.ghostElement, 0.5);
			document.body.appendChild(p.ghostElement);
			//
		},
		dnd_dragStart:function(e){
		},
		dnd_drag:function(e){
		},
		dnd_dragEnd:function(e){
			var p=this.dnd_properties;
			if(!p.accept) return;
			var s=this.targetElement(p.source, {tag:'li'});
			p.source=s;
			if(this.$P.dnd_dropEffect=='move') this.removeTree(s);
		},
		dnd_accept:function(aSOURCE,aTARGET){
			if(!this.$P.dnd_allowed||this.$P.dnd_dropEffect=='none')return false;
			var xvc=xlv.util.findParent(aTARGET,{xlvobject:'*'});
			if(xvc && xvc.objectName()!= this.objectName())return false;
			if(xlv.util.isTag(aTARGET, 'li') || xlv.util.isTag(aTARGET, 'ul')) return false;
			var s=this.targetElement(aSOURCE,{tag:'li'},{xlvobject:'*'});
			var t=this.targetElement(aTARGET,{tag:'li'},{xlvobject:'*'});
			if(!s || !t) return false;
			if(xvc==this && xlv.util.isDescendantOf(t,s)) return false;
			return true;
		},
		dnd_drop:function(e,drag_dnd_object){
			var p=drag_dnd_object.dnd_properties;
			var s=this.targetElement(p.source, {tag:'li'});
			var t=this.targetElement(p.target, {tag:'li'});
			//
			if(this.$P.dnd_dropEffect=='copy') s=s.cloneNode(true);
			switch (this.$P.dnd_dropTarget) {  
				case 'child' : this.appendTreeChild(s, t); break;
				case 'before' : this.insertTreeBefore(s, t); break;
				case 'after' : this.insertTreeAfter(s, t); break;
				default : break;  
			}
		}
	}
};
